﻿package com.designoutput.elements
{
	import com.designoutput.enum.ElementType;
	import com.designoutput.enum.TextHAlign;
	import com.designoutput.enum.TextVAlign;
	import com.designoutput.event.ElementEvent;
	import com.designoutput.manager.fontManagerClasses.FontStyleInfo;
	import com.designoutput.utils.Globals;
	import com.designoutput.utils.Unit;
	import com.designoutput.utils.UnitUtils;
	
	import flash.events.Event;
	import flash.filters.DropShadowFilter;
	import flash.text.AntiAliasType;
	import flash.text.GridFitType;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	
	public class TextElement extends BaseRectElement
	{	
		private var _textField:TextField;
		private var _shadowTextField:TextField;
		private var _textFormat:TextFormat;
		private var _align:String;
		private var _vAlign:String;
		private var _shadow:Boolean;
		private var _editable:Boolean = false;

		public var _text:String;
		
		public function TextElement()
		{
			super();
						
			allowSelectionFilter = false;
			
			fillColor = 0;
			useLine = false;
					
			_shadowTextField = new TextField();
			_shadowTextField.autoSize = TextFieldAutoSize.LEFT;
			_shadowTextField.type = TextFieldType.DYNAMIC;
			_shadowTextField.border = false;
			_shadowTextField.selectable = false;
			_shadowTextField.gridFitType = GridFitType.SUBPIXEL;
			_shadowTextField.antiAliasType = AntiAliasType.ADVANCED;
			_shadowTextField.embedFonts = true;
			_shadowTextField.wordWrap = true;
			_shadowTextField.multiline = true;
			_shadowTextField.addEventListener(Event.CHANGE, onChanged);
			
			_textField = new TextField();
			_textField.autoSize = TextFieldAutoSize.LEFT;
			_textField.type = TextFieldType.INPUT;
			_textField.border = false;
			_textField.selectable = false;
			_textField.gridFitType = GridFitType.SUBPIXEL;
			_textField.antiAliasType = AntiAliasType.ADVANCED;
			_textField.embedFonts = true;
			_textField.wordWrap = true;
			_textField.multiline = true;
			_textField.addEventListener(Event.CHANGE, onChanged);
						
			_textFormat = new TextFormat();
			_textFormat.align = TextHAlign.LEFT;
			_textFormat.color = 0;
			_textFormat.size = 12;
			_textFormat.kerning = true;
			_textFormat.letterSpacing = 0;
			_textFormat.leading = 0;
			_textFormat.font = Globals.fontManager.availableFonts[0].name;
			
			_text = "Text";
			
			_align = TextHAlign.LEFT;
			_vAlign = TextVAlign.TOP;
			_shadow = false;
			
			Globals.fontManager.requireFont(_textFormat, updateElement);
			
			addChild(_textField);
			addChild(_shadowTextField);
		}
		
		override public function getClassName():String
		{
			return ElementType.TextElement;
		}

		public function get text():String
		{
			return _textField.text;
		}
		
		public function set text(value:String):void
		{
			_text = value;		
			invalidateElement();
		}
		
		public function get bold():Boolean {
			return _textFormat.bold;
		}
		
		public function set bold(value:Boolean):void {
			_textFormat.bold = value;
			invalidateElement();
			Globals.fontManager.requireFont(_textFormat, updateElement);
		}
		
		public function get italic():Boolean {
			return _textFormat.italic;
		}
		
		public function set italic(value:Boolean):void {
			_textFormat.italic = value;
			invalidateElement();
			Globals.fontManager.requireFont(_textFormat, updateElement);
		}
		
		public function get underline():Boolean {
			return _textFormat.underline;
		}
		
		public function set underline(value:Boolean):void {
			_textFormat.underline = value;
			invalidateElement();
		}
				
		public function get size():Number {
			return Number(_textFormat.size);
		}
		
		public function set size(value:Number):void {
			_textFormat.size = value;
			invalidateElement();
		}
		
		public function get font():String {
			return _textFormat.font;
		}
		
		public function set font(value:String):void {
			_textFormat.font = value;
			invalidateElement();
			Globals.fontManager.requireFont(_textFormat, updateElement);
		}
				
		public function get kerning():Boolean {
			return Boolean(_textFormat.kerning);
		}
		
		public function set kerning(value:Boolean):void {
			_textFormat.kerning = value;
			invalidateElement();
		}
		
		public function get leading():Number {
			return Number(_textFormat.leading);
		}
		
		public function set leading(value:Number):void {
			_textFormat.leading = value;
			invalidateElement();
		}
		
		public function get letterSpacing():Number {
			return Number(_textFormat.letterSpacing);
		}
		
		public function set letterSpacing(value:Number):void {
			_textFormat.letterSpacing = value;
			invalidateElement();
		}
		
		public function get shadow():Boolean {
			return _shadow;
		}
		
		public function set shadow(value:Boolean):void {
			_shadow = value;
			invalidateElement();
		}
		
		public function get align():String {
			return _align;
		}
		
		public function set align(value:String):void {
			_align = value;
			invalidateElement();
		}
		
		public function get vAlign():String {
			return _vAlign;
		}
		
		public function set vAlign(value:String):void {
			_vAlign = value;
			invalidateElement();
		}

		private function onChanged(evt:Event):void
		{
			_text = _textField.text;
			updateElement();
		}
	
		override public function set selected(value:Boolean):void
		{
			super.selected = value;
			if (!value)
				editable = false;
		}
				
		public function get editable():Boolean {
			return _editable;
		}
		
		override protected function updateElement():void
		{				
			super.updateElement();
			
			//Apply some properties
			alpha = fillAlpha;
			_textFormat.color = fillColor;
			
			switch(align)
			{
				case TextHAlign.LEFT:
					_textFormat.align = TextFormatAlign.LEFT;
					break;
				case TextHAlign.CENTER:
					_textFormat.align = TextFormatAlign.CENTER;
					break;
				case TextHAlign.RIGHT:
					_textFormat.align = TextFormatAlign.RIGHT;
					break;
				case TextHAlign.JUSTIFY:
					_textFormat.align = TextFormatAlign.JUSTIFY;
					break;
			}
			
			//Update Shadow
			_shadowTextField.visible = shadow;
			
			//Update textField and size		
			_shadowTextField.x = _textField.x = 0;
			_shadowTextField.width = _textField.width = Math.max(_width, 30);
			
			_shadowTextField.defaultTextFormat = _textField.defaultTextFormat = _textFormat;
			if(_text != _textField.text)
				_shadowTextField.text = _textField.text = _text;
			_textField.setTextFormat(_textFormat);
			_shadowTextField.setTextFormat(_textFormat);
			
			_shadowTextField.height = _textField.height = _textField.textHeight + 5;
						
			/**
			 * update the width and height, so it could resize the text box size easily
			 * */
			var w:Number = Math.max(_width, 30);
			var h:Number = Math.max(_textField.height, _height, 15);
			
			if(_width != w || _height != h)
			{
				_width = w;
				_height = h;
				dispatchEvent(new ElementEvent(ElementEvent.TRANSFORM_CHANGED));
			}
			
			//Update VAlign
			switch (_vAlign)
			{
				case TextVAlign.TOP:
					_shadowTextField.y = _textField.y = 0;
					break;
				case TextVAlign.MIDDLE:
					_shadowTextField.y = _textField.y = Math.floor((_height - _textField.textHeight) / 2);
					break;
				case TextVAlign.BOTTOM:
					_shadowTextField.y = _textField.y = _height - _textField.textHeight;
					break;
			}
			
			_shadowTextField.x += Math.cos(Math.PI/4)*2;
			_shadowTextField.y += Math.sin(Math.PI/4)*2;
			
			_shadowTextField.alpha = 0.3;
		}
		
		public function set editable(value:Boolean):void
		{
			_editable = value;
			_textField.selectable = value;
			mouseEnabled = _editable;
			
			if(_editable){
				Globals.focusManager.setFocus(_textField);
				_textField.setSelection(0, _text.length);
			}else{
				_textField.setSelection(0, 0);
			}
			
			updateElement();
		}

		override public function toXML():XML
		{
			var elementXML:XML = super.toXML();
			
			elementXML.@text = _text;
			
			elementXML.@bold = bold ? "true" : "false";
			elementXML.@italic = italic ? "true" : "false";
			elementXML.@underline = underline ? "true" : "false";
			
			elementXML.@size = UnitUtils.convert(size, Unit.PIXELS, Unit.POINTS);
			elementXML.@font = font;
			
			elementXML.@kerning = kerning ? "true" : "false";
			elementXML.@letterSpacing = UnitUtils.convert(letterSpacing, Unit.PIXELS, Unit.POINTS);
			elementXML.@leading = leading;
			
			elementXML.@align = align;
			elementXML.@valign = vAlign;
			
			elementXML.@shadow = shadow ? "true" : "false";
			
			return elementXML;
		}

		override public function fromXML(xmlNode:XML):void
		{
			super.fromXML(xmlNode);
			
			text = xmlNode.@text;
			
			bold = String(xmlNode.@bold) == "true";
			italic = String(xmlNode.@italic) == "true";
			underline = String(xmlNode.@underline) == "true";

			size = UnitUtils.convert(Number(xmlNode.@size), Unit.POINTS, Unit.PIXELS);
			font = String(xmlNode.@font);
			
			kerning = String(xmlNode.@kerning) == "true";
			letterSpacing = UnitUtils.convert(Number(xmlNode.@letterSpacing), Unit.POINTS, Unit.PIXELS);
			leading = Number(xmlNode.@leading);
			
			align = String(xmlNode.@align);
			vAlign = String(xmlNode.@valign);
			
			shadow = String(xmlNode.@shadow) == "true";
		}
	}
}